Convert python 2 check hash to python 3












1















I need to transfer users and their passwords from a python 2 system to a python 3 system.



The PW hash looks like this:



PBKDF2$sha256$10000$KlCW+ewerd19fS9f$l+5LgvcWTzghtz77086MSVG+q5z2Lij


In the python 2 system I used these functions to check hashes:



def check_hash(password, hash_):
"""Check a password against an existing hash."""
if isinstance(password, unicode):
password = password.encode('utf-8')
algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$')
assert algorithm == 'PBKDF2'
hash_a = b64decode(hash_a)
hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a),
getattr(hashlib, hash_function))
assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin()
# Same as "return hash_a == hash_b" but takes a constant time.
# See http://carlos.bueno.org/2011/10/timing.html
diff = 0
for char_a, char_b in izip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)
return diff == 0


and this:



_pack_int = Struct('>I').pack

def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
"""Returns a binary digest for the PBKDF2 hash algorithm of `data`
with the given `salt`. It iterates `iterations` time and produces a
key of `keylen` bytes. By default SHA-1 is used as hash function,
a different hashlib `hashfunc` can be provided.
"""
hashfunc = hashfunc or hashlib.sha1
mac = hmac.new(data, None, hashfunc)
def _pseudorandom(x, mac=mac):
h = mac.copy()
h.update(x)
return map(ord, h.digest())
buf =
for block in xrange(1, -(-keylen // mac.digest_size) + 1):
rv = u = _pseudorandom(salt + _pack_int(block))
for i in xrange(iterations - 1):
u = _pseudorandom(''.join(map(chr, u)))
rv = starmap(xor, izip(rv, u))
buf.extend(rv)
return ''.join(map(chr, buf))[:keylen]


What have I done so far:



Right after copying the code into my python 3 scripts I had to change some variables:



izip -> zip



I kept unicode: from past.builtins import unicode



I kept xrange: from past.builtins import xrange



Now I had no script errors, but after executing the script I got an error here (in the pbkdf2_bin function):



rv = u = _pseudorandom(salt + _pack_int(block))
TypeError: must be str, not bytes


So I fixed it by converting bytes to str:



rv = u = _pseudorandom(salt + _pack_int(block).decode('utf-8'))


Now the next error appears (in the pbkdf2_bin function):



h.update(x)
TypeError: Unicode-objects must be encoded before hashing


I also fixed this with the proper encoding:



h.update(x.encode('utf-8'))


Next error:



  File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredhash_passwords.py", line 123, in check_hash
getattr(hashlib, hash_function))
File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredpbkdf2.py", line 125, in pbkdf2_bin_old_2
u = _pseudorandom(''.join(map(chr, u)))
TypeError: ord() expected string of length 1, but int found


There was an issue with the return value of _pseudorandom (in the pbkdf2_bin function). It had to be converted, so I fixed it:



Maybe the issue is here



#return map(ord, h.digest()) # throws the error
#return map(int, h.digest()) # returns nothing (length 0)
#return list(map(ord, h.digest())) # throws the error
return list(map(int, h.digest())) # seems to work with the correct length


The last error is at the end of the check_hash function:



File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredhash_passwords.py", line 129, in check_hash
diff |= ord(char_a) ^ ord(char_b)
TypeError: ord() expected string of length 1, but int found

for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)


char_a is an integer and chat_b is not. I was able to fix this by converting char_a to the real char:



for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(chr(char_a)) ^ ord(char_b)


Finally I had no errors, but it tells me the entered password is wrong,
so somewhere is an error, because I know that the password is correct and it works on the python 2 app.



EDIT



Someone mentioned the 2to3 library, so I tried it. All in all it has done the same things, which I have done already and the problem is the same.










share|improve this question

























  • I would just try h.update(x) => h.update(x.encode("utf-8"))

    – Jean-François Fabre
    yesterday











  • I am doing this already, you missed it, while reading the question. I know its long. Thanks for the reply!

    – Roman
    yesterday











  • Aside, but out of curiosity: if you want to convert the code to Python 3, why keep unicode and xrange, instead of replacing them with their Python 3 equivalents?

    – 9769953
    yesterday











  • You should do some proper debugging: litter some print statements/functions in both codes, then compare all intermediate values (it may compare str and bytes, but the contents should be the same). That may show you where the scripts go wrong.

    – 9769953
    yesterday











  • I have done all this already, I didnt wanted to post all prints and tests as it would be a lot more code and would look messy. I hoped that someone would immediately recognize the issue, but as it seems, its a very hard issue. Thanks for the reply!

    – Roman
    yesterday
















1















I need to transfer users and their passwords from a python 2 system to a python 3 system.



The PW hash looks like this:



PBKDF2$sha256$10000$KlCW+ewerd19fS9f$l+5LgvcWTzghtz77086MSVG+q5z2Lij


In the python 2 system I used these functions to check hashes:



def check_hash(password, hash_):
"""Check a password against an existing hash."""
if isinstance(password, unicode):
password = password.encode('utf-8')
algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$')
assert algorithm == 'PBKDF2'
hash_a = b64decode(hash_a)
hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a),
getattr(hashlib, hash_function))
assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin()
# Same as "return hash_a == hash_b" but takes a constant time.
# See http://carlos.bueno.org/2011/10/timing.html
diff = 0
for char_a, char_b in izip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)
return diff == 0


and this:



_pack_int = Struct('>I').pack

def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
"""Returns a binary digest for the PBKDF2 hash algorithm of `data`
with the given `salt`. It iterates `iterations` time and produces a
key of `keylen` bytes. By default SHA-1 is used as hash function,
a different hashlib `hashfunc` can be provided.
"""
hashfunc = hashfunc or hashlib.sha1
mac = hmac.new(data, None, hashfunc)
def _pseudorandom(x, mac=mac):
h = mac.copy()
h.update(x)
return map(ord, h.digest())
buf =
for block in xrange(1, -(-keylen // mac.digest_size) + 1):
rv = u = _pseudorandom(salt + _pack_int(block))
for i in xrange(iterations - 1):
u = _pseudorandom(''.join(map(chr, u)))
rv = starmap(xor, izip(rv, u))
buf.extend(rv)
return ''.join(map(chr, buf))[:keylen]


What have I done so far:



Right after copying the code into my python 3 scripts I had to change some variables:



izip -> zip



I kept unicode: from past.builtins import unicode



I kept xrange: from past.builtins import xrange



Now I had no script errors, but after executing the script I got an error here (in the pbkdf2_bin function):



rv = u = _pseudorandom(salt + _pack_int(block))
TypeError: must be str, not bytes


So I fixed it by converting bytes to str:



rv = u = _pseudorandom(salt + _pack_int(block).decode('utf-8'))


Now the next error appears (in the pbkdf2_bin function):



h.update(x)
TypeError: Unicode-objects must be encoded before hashing


I also fixed this with the proper encoding:



h.update(x.encode('utf-8'))


Next error:



  File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredhash_passwords.py", line 123, in check_hash
getattr(hashlib, hash_function))
File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredpbkdf2.py", line 125, in pbkdf2_bin_old_2
u = _pseudorandom(''.join(map(chr, u)))
TypeError: ord() expected string of length 1, but int found


There was an issue with the return value of _pseudorandom (in the pbkdf2_bin function). It had to be converted, so I fixed it:



Maybe the issue is here



#return map(ord, h.digest()) # throws the error
#return map(int, h.digest()) # returns nothing (length 0)
#return list(map(ord, h.digest())) # throws the error
return list(map(int, h.digest())) # seems to work with the correct length


The last error is at the end of the check_hash function:



File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredhash_passwords.py", line 129, in check_hash
diff |= ord(char_a) ^ ord(char_b)
TypeError: ord() expected string of length 1, but int found

for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)


char_a is an integer and chat_b is not. I was able to fix this by converting char_a to the real char:



for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(chr(char_a)) ^ ord(char_b)


Finally I had no errors, but it tells me the entered password is wrong,
so somewhere is an error, because I know that the password is correct and it works on the python 2 app.



EDIT



Someone mentioned the 2to3 library, so I tried it. All in all it has done the same things, which I have done already and the problem is the same.










share|improve this question

























  • I would just try h.update(x) => h.update(x.encode("utf-8"))

    – Jean-François Fabre
    yesterday











  • I am doing this already, you missed it, while reading the question. I know its long. Thanks for the reply!

    – Roman
    yesterday











  • Aside, but out of curiosity: if you want to convert the code to Python 3, why keep unicode and xrange, instead of replacing them with their Python 3 equivalents?

    – 9769953
    yesterday











  • You should do some proper debugging: litter some print statements/functions in both codes, then compare all intermediate values (it may compare str and bytes, but the contents should be the same). That may show you where the scripts go wrong.

    – 9769953
    yesterday











  • I have done all this already, I didnt wanted to post all prints and tests as it would be a lot more code and would look messy. I hoped that someone would immediately recognize the issue, but as it seems, its a very hard issue. Thanks for the reply!

    – Roman
    yesterday














1












1








1








I need to transfer users and their passwords from a python 2 system to a python 3 system.



The PW hash looks like this:



PBKDF2$sha256$10000$KlCW+ewerd19fS9f$l+5LgvcWTzghtz77086MSVG+q5z2Lij


In the python 2 system I used these functions to check hashes:



def check_hash(password, hash_):
"""Check a password against an existing hash."""
if isinstance(password, unicode):
password = password.encode('utf-8')
algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$')
assert algorithm == 'PBKDF2'
hash_a = b64decode(hash_a)
hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a),
getattr(hashlib, hash_function))
assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin()
# Same as "return hash_a == hash_b" but takes a constant time.
# See http://carlos.bueno.org/2011/10/timing.html
diff = 0
for char_a, char_b in izip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)
return diff == 0


and this:



_pack_int = Struct('>I').pack

def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
"""Returns a binary digest for the PBKDF2 hash algorithm of `data`
with the given `salt`. It iterates `iterations` time and produces a
key of `keylen` bytes. By default SHA-1 is used as hash function,
a different hashlib `hashfunc` can be provided.
"""
hashfunc = hashfunc or hashlib.sha1
mac = hmac.new(data, None, hashfunc)
def _pseudorandom(x, mac=mac):
h = mac.copy()
h.update(x)
return map(ord, h.digest())
buf =
for block in xrange(1, -(-keylen // mac.digest_size) + 1):
rv = u = _pseudorandom(salt + _pack_int(block))
for i in xrange(iterations - 1):
u = _pseudorandom(''.join(map(chr, u)))
rv = starmap(xor, izip(rv, u))
buf.extend(rv)
return ''.join(map(chr, buf))[:keylen]


What have I done so far:



Right after copying the code into my python 3 scripts I had to change some variables:



izip -> zip



I kept unicode: from past.builtins import unicode



I kept xrange: from past.builtins import xrange



Now I had no script errors, but after executing the script I got an error here (in the pbkdf2_bin function):



rv = u = _pseudorandom(salt + _pack_int(block))
TypeError: must be str, not bytes


So I fixed it by converting bytes to str:



rv = u = _pseudorandom(salt + _pack_int(block).decode('utf-8'))


Now the next error appears (in the pbkdf2_bin function):



h.update(x)
TypeError: Unicode-objects must be encoded before hashing


I also fixed this with the proper encoding:



h.update(x.encode('utf-8'))


Next error:



  File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredhash_passwords.py", line 123, in check_hash
getattr(hashlib, hash_function))
File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredpbkdf2.py", line 125, in pbkdf2_bin_old_2
u = _pseudorandom(''.join(map(chr, u)))
TypeError: ord() expected string of length 1, but int found


There was an issue with the return value of _pseudorandom (in the pbkdf2_bin function). It had to be converted, so I fixed it:



Maybe the issue is here



#return map(ord, h.digest()) # throws the error
#return map(int, h.digest()) # returns nothing (length 0)
#return list(map(ord, h.digest())) # throws the error
return list(map(int, h.digest())) # seems to work with the correct length


The last error is at the end of the check_hash function:



File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredhash_passwords.py", line 129, in check_hash
diff |= ord(char_a) ^ ord(char_b)
TypeError: ord() expected string of length 1, but int found

for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)


char_a is an integer and chat_b is not. I was able to fix this by converting char_a to the real char:



for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(chr(char_a)) ^ ord(char_b)


Finally I had no errors, but it tells me the entered password is wrong,
so somewhere is an error, because I know that the password is correct and it works on the python 2 app.



EDIT



Someone mentioned the 2to3 library, so I tried it. All in all it has done the same things, which I have done already and the problem is the same.










share|improve this question
















I need to transfer users and their passwords from a python 2 system to a python 3 system.



The PW hash looks like this:



PBKDF2$sha256$10000$KlCW+ewerd19fS9f$l+5LgvcWTzghtz77086MSVG+q5z2Lij


In the python 2 system I used these functions to check hashes:



def check_hash(password, hash_):
"""Check a password against an existing hash."""
if isinstance(password, unicode):
password = password.encode('utf-8')
algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$')
assert algorithm == 'PBKDF2'
hash_a = b64decode(hash_a)
hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a),
getattr(hashlib, hash_function))
assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin()
# Same as "return hash_a == hash_b" but takes a constant time.
# See http://carlos.bueno.org/2011/10/timing.html
diff = 0
for char_a, char_b in izip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)
return diff == 0


and this:



_pack_int = Struct('>I').pack

def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
"""Returns a binary digest for the PBKDF2 hash algorithm of `data`
with the given `salt`. It iterates `iterations` time and produces a
key of `keylen` bytes. By default SHA-1 is used as hash function,
a different hashlib `hashfunc` can be provided.
"""
hashfunc = hashfunc or hashlib.sha1
mac = hmac.new(data, None, hashfunc)
def _pseudorandom(x, mac=mac):
h = mac.copy()
h.update(x)
return map(ord, h.digest())
buf =
for block in xrange(1, -(-keylen // mac.digest_size) + 1):
rv = u = _pseudorandom(salt + _pack_int(block))
for i in xrange(iterations - 1):
u = _pseudorandom(''.join(map(chr, u)))
rv = starmap(xor, izip(rv, u))
buf.extend(rv)
return ''.join(map(chr, buf))[:keylen]


What have I done so far:



Right after copying the code into my python 3 scripts I had to change some variables:



izip -> zip



I kept unicode: from past.builtins import unicode



I kept xrange: from past.builtins import xrange



Now I had no script errors, but after executing the script I got an error here (in the pbkdf2_bin function):



rv = u = _pseudorandom(salt + _pack_int(block))
TypeError: must be str, not bytes


So I fixed it by converting bytes to str:



rv = u = _pseudorandom(salt + _pack_int(block).decode('utf-8'))


Now the next error appears (in the pbkdf2_bin function):



h.update(x)
TypeError: Unicode-objects must be encoded before hashing


I also fixed this with the proper encoding:



h.update(x.encode('utf-8'))


Next error:



  File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredhash_passwords.py", line 123, in check_hash
getattr(hashlib, hash_function))
File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredpbkdf2.py", line 125, in pbkdf2_bin_old_2
u = _pseudorandom(''.join(map(chr, u)))
TypeError: ord() expected string of length 1, but int found


There was an issue with the return value of _pseudorandom (in the pbkdf2_bin function). It had to be converted, so I fixed it:



Maybe the issue is here



#return map(ord, h.digest()) # throws the error
#return map(int, h.digest()) # returns nothing (length 0)
#return list(map(ord, h.digest())) # throws the error
return list(map(int, h.digest())) # seems to work with the correct length


The last error is at the end of the check_hash function:



File "C:UsersUserEclipse-WorkspaceMonteurzimmer-Remasteredhash_passwords.py", line 129, in check_hash
diff |= ord(char_a) ^ ord(char_b)
TypeError: ord() expected string of length 1, but int found

for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)


char_a is an integer and chat_b is not. I was able to fix this by converting char_a to the real char:



for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(chr(char_a)) ^ ord(char_b)


Finally I had no errors, but it tells me the entered password is wrong,
so somewhere is an error, because I know that the password is correct and it works on the python 2 app.



EDIT



Someone mentioned the 2to3 library, so I tried it. All in all it has done the same things, which I have done already and the problem is the same.







python python-3.x hash python-unicode






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited yesterday







Roman

















asked yesterday









RomanRoman

6961738




6961738













  • I would just try h.update(x) => h.update(x.encode("utf-8"))

    – Jean-François Fabre
    yesterday











  • I am doing this already, you missed it, while reading the question. I know its long. Thanks for the reply!

    – Roman
    yesterday











  • Aside, but out of curiosity: if you want to convert the code to Python 3, why keep unicode and xrange, instead of replacing them with their Python 3 equivalents?

    – 9769953
    yesterday











  • You should do some proper debugging: litter some print statements/functions in both codes, then compare all intermediate values (it may compare str and bytes, but the contents should be the same). That may show you where the scripts go wrong.

    – 9769953
    yesterday











  • I have done all this already, I didnt wanted to post all prints and tests as it would be a lot more code and would look messy. I hoped that someone would immediately recognize the issue, but as it seems, its a very hard issue. Thanks for the reply!

    – Roman
    yesterday



















  • I would just try h.update(x) => h.update(x.encode("utf-8"))

    – Jean-François Fabre
    yesterday











  • I am doing this already, you missed it, while reading the question. I know its long. Thanks for the reply!

    – Roman
    yesterday











  • Aside, but out of curiosity: if you want to convert the code to Python 3, why keep unicode and xrange, instead of replacing them with their Python 3 equivalents?

    – 9769953
    yesterday











  • You should do some proper debugging: litter some print statements/functions in both codes, then compare all intermediate values (it may compare str and bytes, but the contents should be the same). That may show you where the scripts go wrong.

    – 9769953
    yesterday











  • I have done all this already, I didnt wanted to post all prints and tests as it would be a lot more code and would look messy. I hoped that someone would immediately recognize the issue, but as it seems, its a very hard issue. Thanks for the reply!

    – Roman
    yesterday

















I would just try h.update(x) => h.update(x.encode("utf-8"))

– Jean-François Fabre
yesterday





I would just try h.update(x) => h.update(x.encode("utf-8"))

– Jean-François Fabre
yesterday













I am doing this already, you missed it, while reading the question. I know its long. Thanks for the reply!

– Roman
yesterday





I am doing this already, you missed it, while reading the question. I know its long. Thanks for the reply!

– Roman
yesterday













Aside, but out of curiosity: if you want to convert the code to Python 3, why keep unicode and xrange, instead of replacing them with their Python 3 equivalents?

– 9769953
yesterday





Aside, but out of curiosity: if you want to convert the code to Python 3, why keep unicode and xrange, instead of replacing them with their Python 3 equivalents?

– 9769953
yesterday













You should do some proper debugging: litter some print statements/functions in both codes, then compare all intermediate values (it may compare str and bytes, but the contents should be the same). That may show you where the scripts go wrong.

– 9769953
yesterday





You should do some proper debugging: litter some print statements/functions in both codes, then compare all intermediate values (it may compare str and bytes, but the contents should be the same). That may show you where the scripts go wrong.

– 9769953
yesterday













I have done all this already, I didnt wanted to post all prints and tests as it would be a lot more code and would look messy. I hoped that someone would immediately recognize the issue, but as it seems, its a very hard issue. Thanks for the reply!

– Roman
yesterday





I have done all this already, I didnt wanted to post all prints and tests as it would be a lot more code and would look messy. I hoped that someone would immediately recognize the issue, but as it seems, its a very hard issue. Thanks for the reply!

– Roman
yesterday












0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54251824%2fconvert-python-2-check-hash-to-python-3%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54251824%2fconvert-python-2-check-hash-to-python-3%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Liquibase includeAll doesn't find base path

How to use setInterval in EJS file?

Petrus Granier-Deferre